﻿using System;
using System.Linq;

namespace DotNetCommon.Extensions;

/// <summary>
/// 数组扩展类
/// </summary>
public static class ArrayExtensions
{
    #region 循环操作 Next/Pre/ReverseFluent/ReSetStart
    /// <summary>
    /// 循环操作场景(一个多边形的点位遍历), 返回指定索引的下一个元素,如:
    /// <code>
    /// new Vector2[] { new(0, 0), new(1, 0), new(1, 1) }.Next(2).ShouldBe(new(0, 0));
    /// </code>
    /// </summary>
    public static T Next<T>(this T[] arr, int currentIndex)
    {
        return arr[(currentIndex + 1) % arr.Length];
    }
    /// <summary>
    /// 循环操作场景(一个多边形的点位遍历),返回指定索引的上一个元素,如:
    /// <code>
    /// new Vector2[] { new(0, 0), new(1, 0), new(1, 1) }.Pre(0).ShouldBe(new(1, 1));
    /// </code>
    /// </summary>
    public static T Pre<T>(this T[] arr, int currentIndex)
    {
        return arr[(currentIndex - 1 + arr.Length) % arr.Length];
    }
    /// <summary>
    /// 将自身翻转, 并返回自身,如下:
    /// <code>
    /// new int[] { 1, 2, 3, 4 }.ReverseFluent().ShouldBe(new int[] { 4, 3, 2, 1 });
    /// </code>
    /// </summary>
    public static T[] ReverseFluent<T>(this T[] arr)
    {
        for (int i = 0; i < arr.Length / 2; i++)
        {
            (arr[i], arr[arr.Length - i - 1]) = (arr[arr.Length - i - 1], arr[i]);
        }
        return arr;
    }
    /// <summary>
    /// 旋转集合, 使 <c>index</c> 位置的元素作为新的起始元素, 返回新的集合, 如下:
    /// <code>
    /// new int[] { 1, 2, 3, 4 }.ReSetStart(2).ShouldBe(new int[] { 3, 4, 1, 2 });
    /// new int[] { 1, 2, 3, 4 }.ReSetStart(-1).ShouldBe(new int[] { 4, 1, 2, 3 });
    /// </code>
    /// </summary>
    public static T[] ReSetStart<T>(this T[] arr, int startIndex, bool reverse = false)
    {
        startIndex %= arr.Length;
        if (startIndex < 0) startIndex += arr.Length;
        if (reverse)
        {
            return arr.Take(startIndex + 1).Reverse().Concat(arr.Skip(startIndex + 1).Take(arr.Length - startIndex - 1).Reverse()).ToArray();
        }
        else
        {
            return arr.Skip(startIndex).Take(arr.Length - startIndex).Concat(arr.Take(startIndex)).ToArray();
        }
    }
    #endregion

    #region Fluent风格 T[] SetFluent
    /// <summary>
    /// Fluent风格: 设置数组中指定索引的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果数组为null或索引超出,抛出异常</item>
    /// </list>
    /// </remarks>
    public static T[] SetFluent<T>(this T[] arr, int index, T b)
    {
        arr[index] = b;
        return arr;
    }

    /// <summary>
    /// Fluent风格: 设置数组中指定索引的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果数组为null或索引超出,抛出异常</item>
    /// </list>
    /// </remarks>
    public static T[] SetUpdateFluent<T>(this T[] arr, int index, Func<T, T> func)
    {
        if (func == null) return arr;
        arr[index] = func(arr[index]);
        return arr;
    }

    /// <summary>
    /// Fluent风格: 批量设置数组中的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果数组为null或索引超出,抛出异常</item>
    /// </list>
    /// </remarks>
    public static T[] SetUpdateFluent<T>(this T[] arr, Func<T, bool> filter, Func<T, T> func)
    {
        if (func == null) return arr;
        for (int i = 0; i < arr.Length; i++)
        {
            var b = filter?.Invoke(arr[i]);
            if (b == false) continue;
            arr[i] = func(arr[i]);
        }
        return arr;
    }
    #endregion

    #region FindIndex FindLastIndex
    /// <summary>
    /// 类似 list.FindIndex
    /// </summary>
    public static int FindIndex<T>(this T[] arr, Predicate<T> match)
    {
        for (int i = 0; i < arr.Length; i++)
        {
            if (match(arr[i])) return i;
        }
        return -1;
    }
    /// <summary>
    /// 类似 list.FindLastIndex
    /// </summary>
    public static int FindLastIndex<T>(this T[] arr, Predicate<T> match)
    {
        for (int i = arr.Length - 1; i >= 0; i--)
        {
            if (match(arr[i])) return i;
        }
        return -1;
    }
    #endregion
}
